/*
 * Created: Author: Aléx Carvalho / Date: 6/mai/2015
 * 
 * Changed: $Author: ac280593@gmail.com $ / $Date: 2015-06-11 04:28:43 +0000 (Thu, 11 Jun 2015) $
 */
package com.cpm.jobs.performance;

import com.cpm.ServiceLocator;
import com.cpm.business.PerformanceCalculator;
import com.cpm.context.SystemLogger;
import com.cpm.entities.Competence;
import com.cpm.entities.Folder;
import com.cpm.entities.Folder_;
import com.cpm.entities.Indicator;
import com.cpm.entities.StrategicPlan;
import com.cpm.entities.StrategicPlan_;
import com.cpm.entities.converters.TypeConverter;
import com.cpm.entities.id.IntegerId;
import com.cpm.entities.types.Family;
import static com.cpm.entities.types.IndicatorModeType.AVERAGE;
import static com.cpm.entities.types.IndicatorModeType.CUMULATIVE;
import com.cpm.repository.Filter;
import com.cpm.wrapper.CompetenceList;
import com.cpm.wrapper.Performance;
import com.cpm.wrapper.SolidObjects;
import com.cpm.wrapper.exception.SystemException;
import java.time.LocalDate;
import java.time.Year;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import javax.batch.api.AbstractBatchlet;
import javax.batch.runtime.BatchRuntime;
import javax.batch.runtime.BatchStatus;
import javax.batch.runtime.context.JobContext;
import javax.inject.Named;
import javax.persistence.NoResultException;

@Named
public class PerformanceBatchlet extends AbstractBatchlet {

    private final PerformanceCalculator performanceCalculator;

    public PerformanceBatchlet() {
        performanceCalculator = ServiceLocator.lookup(PerformanceCalculator.class);
    }

    @Override
    public String process() throws Exception {
        try {
            Properties parameters = BatchRuntime.getJobOperator().getParameters(ServiceLocator.lookup(JobContext.class).getExecutionId());

            String fam = SolidObjects.notNull(parameters.getProperty("family"));

            Family family = SolidObjects.notNull(TypeConverter.convertTo(Family.class, fam));

            Object value = null;

            if (family == Family.COMPETENCE) {
                LocalDate period = LocalDate.parse(parameters.getProperty("competencePeriod"));
                Integer indicatorId = Integer.parseInt(parameters.getProperty("indicatorId"));

                Indicator ind = ServiceLocator.getIndicatorRepository().findById(new IntegerId(indicatorId));

                CompetenceList cl = ind.getCompetenceList();

                value = cl.getCompetenceByLocalDate(period);
            }
            else if (family == Family.INDICATOR) {
            }

            recursive(value);
        }
        catch (NoResultException e) {
            SystemLogger.logException(e);
            return BatchStatus.FAILED.toString();
        }

        return BatchStatus.COMPLETED.toString();
    }

    private void recursive(Object obj) {
        if (obj instanceof Competence) {

            Competence c = (Competence) obj;

            Performance performance = performanceCalculator.calculatePerformanceCompetence(c);

            if (c.getPerformance() != performance) {

                c.setPerformance(performance);

                ServiceLocator.getCompetenceRepository().update(c);

                Indicator indicator = c.getIndicator();

                if (indicator.getMode() == AVERAGE || indicator.getMode() == CUMULATIVE) {

                    LocalDate date = c.getPeriod();

                    Collection<Competence> competences = indicator.getCompetenceList().getCompetencesLarger(Year.of(date.getYear()), date.getMonth());

                    for (Competence comp : competences) {

                        Performance perf = performanceCalculator.calculatePerformanceCompetence(comp);

                        // TODO: Controle pra parar atualização se resultado for igual
//                        if (comp.getPerformance().equals(perf)) {
//                            break;
//                        }
                        comp.setPerformance(perf);

                        ServiceLocator.getCompetenceRepository().update(comp);
                    }
                }
//
                recursive(indicator);
            }

        }
        else if (obj instanceof Indicator) {
            Indicator ind = (Indicator) obj;

            //PENDING: periodo corrente
            LocalDate current = LocalDate.now().plusMonths(1);

            Competence competence = ind.getCompetenceList().getCompetenceByYearAndMonth(Year.of(current.getYear()), current.getMonth());

            Performance performance = competence.getPerformance();

            if (performance == null) {
                List<Competence> competences = ind.getCompetenceList().getCompetencesSmaller(Year.of(current.getYear()), current.getMonth());

                for (int i = competences.size() - 1; i >= 0; i--) {
                    Competence c = competences.get(i);

                    performance = c.getPerformance();

                    if (performance != null) {
                        break;
                    }
                }
            }

            ind.setPerformance(performance);

            ServiceLocator.getIndicatorRepository().update(ind);

            //calculo
            recursive(getParent(ind.getParentFamily(), ind.getParentId()));
        }

        else if (obj instanceof Folder) {
            Folder folder = (Folder) obj;

            folder.setPerformance(performanceCalculator.calculatePerformanceFolder(folder));

            ServiceLocator.getFolderRepository().update(folder);

            recursive(getParent(folder.getParentFamily(), folder.getParentId()));
        }

        else if (obj instanceof StrategicPlan) {
            StrategicPlan plan = (StrategicPlan) obj;

            plan.setPerformance(performanceCalculator.calculatePerformanceStrategicPlan(plan));

            ServiceLocator.getStrategicPlanRepository().update(plan);
        }

        else if (obj != null) {
            SystemLogger.logException(new SystemException("job Performance not suport parameter value " + obj));
        }
    }

    private Object getParent(Family family, Integer id) {
        Object obj = null;

        Filter filter = ServiceLocator.getFilter();

        if (family == Family.FOLDER) {
            filter.andEquals(Folder_.id, id);
            obj = filter.getSingleResult(Folder.class);
        }
        else if (family == Family.INDICATOR) {
//            filter.andEquals(Indicator_.id, id);
//            obj = filter.getSingleResult(Indicator.class);

            // verificar se precisa quando o parent é um indicador
        }
        else if (family == Family.STRATEGIC_PLAN) {
            filter.andEquals(StrategicPlan_.id, id);
            obj = filter.getSingleResult(StrategicPlan.class);
        }

        return obj;
    }

}
